package com.foreveross.bsl.auth.support.servlet.filter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.ResourceBundle;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.foreveross.bsl.auth.constant.Constant;
import com.foreveross.bsl.auth.integration.ChannelIntegration;
import com.foreveross.bsl.auth.integration.ChannelIntegrationBuilder;
import com.foreveross.bsl.common.utils.bean.ExceptionUtils;
import com.foreveross.bsl.common.utils.context.ContextThead;
import com.foreveross.bsl.common.utils.exception.AppExcType;
import com.foreveross.bsl.common.utils.exception.ApplicationException;

/**
 * @description
 * 
 * @author rening
 * @version v1.0
 * 
 * @2013-7-22
 * 
 */
public class CommonFilter implements Filter {

	private Logger log = LoggerFactory.getLogger(CommonFilter.class);

	private Map<String, String> resLib = new HashMap<String, String>();

	public String getResource(HttpServletRequest httpServletRequest) {
		StringBuffer resource = new StringBuffer();
		// if(httpServletRequest.getServletPath() != null){
		// resource.append(httpServletRequest.getServletPath());
		// }
		if (httpServletRequest.getPathInfo() != null) {
			resource.append(httpServletRequest.getPathInfo());
		}
		return resource.toString();
	}

	public String getUri(HttpServletRequest httpServletRequest) {
		String resource = httpServletRequest.getRequestURI();
		return resource;
	}

	public String getMethod(HttpServletRequest httpServletRequest) {
		String method = httpServletRequest.getMethod();
		return method;
	}

	public String getClientIP(HttpServletRequest httpServletRequest) {
		String ip = httpServletRequest.getRemoteHost();
		return ip;
	}

	@SuppressWarnings("rawtypes")
	public Map getParameters(HttpServletRequest httpServletRequest) {
		Map parameters = httpServletRequest.getParameterMap();
		return parameters;
	}

	public String getIdentity(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
		log.debug("Method getIdentity()...");
		String sessionKey = null;
		try {
			String encodedAuth = httpServletRequest.getHeader(Constant.SESSION_KEY);
			if (encodedAuth == null || "".equals(encodedAuth)) {
				encodedAuth = httpServletRequest.getParameter(Constant.SESSION_KEY);
			}
			if (encodedAuth != null && !"".equals(encodedAuth)) {
				// @SuppressWarnings("restriction")
				// sun.misc.BASE64Decoder decoder = new
				// sun.misc.BASE64Decoder();
				// @SuppressWarnings("restriction")
				// byte[] decodedBytes = decoder.decodeBuffer(encodedAuth);
				// appKey = new String(decodedBytes);
				sessionKey = encodedAuth;
				ContextThead.setThreadSessionKey(sessionKey); // 每次请求都会重置线程里的sessionKey
			}
		} catch (Exception e) {
			log.error("Method getIdentity() Exception " + e.getMessage());
			throw new ApplicationException(AppExcType.SYS_TYPE, AppExcType.INFRA_LAYER, "00", "001", "fetch sessionKey exception");
		}
		log.info("Method getIdentity() finish");
		return sessionKey;
	}

	public HttpServletRequest getHttpServletRequest(ServletRequest request) {
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		return httpServletRequest;
	}

	public HttpServletResponse getHttpServletResponse(ServletResponse response) {
		HttpServletResponse httpServletResponse = (HttpServletResponse) response;
		return httpServletResponse;
	}

	public void init(FilterConfig config) throws ServletException {
		ResourceBundle rb = ResourceBundle.getBundle("resources");
		for (Iterator iterator = rb.keySet().iterator(); iterator.hasNext();) {
			String key = (String) iterator.next();
			resLib.put(key, rb.getString(key));
		}
	}

	@SuppressWarnings("rawtypes")
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		log.debug("Method doFilter()...");
		
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		HttpServletResponse httpServletResponse = (HttpServletResponse) response;

		String sessionKey = this.getIdentity(httpServletRequest, httpServletResponse);
		log.debug("sessionKey: {}", sessionKey);
		
		if (checkPass(httpServletRequest)) {
			chain.doFilter(httpServletRequest, httpServletResponse);
		} else {
			String template = "{\"result\":\"false\",\"code\":\"{key}\",\"message\":\"{value}\"}";
			try {
				if (StringUtils.isBlank(sessionKey)) {
					throw new ApplicationException(AppExcType.BUS_TYPE, AppExcType.INFRA_LAYER, "00", "001", "sessionKey is null");
				}
				Map parameters = this.getParameters(httpServletRequest);
				log.debug("dsRouter: {}", ContextThead.getThreadVar()); // 登录时设置的租户名，建议添加到session中
				
				// 从BeanFactory中获取ticketChannelIntegration对象 
				ChannelIntegration ticketChannelIntegration = ChannelIntegrationBuilder.newInstance();
				// 校验登录
				if (!ticketChannelIntegration.validateIdentity(sessionKey, parameters)) {
					throw new ApplicationException(AppExcType.BUS_TYPE, AppExcType.INFRA_LAYER, "00", "002", "Without permission");
				}
				chain.doFilter(request, response);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				if (e instanceof ApplicationException) {
					ApplicationException a = (ApplicationException) e;
					log.error(a.getCode() + ":" + a.getMessage());
					template = template.replace("{key}", a.getCode()).replace("{value}", ExceptionUtils.formatException(a));
				} else {
					template = template.replace("{key}", "00000000").replace("{value}", ExceptionUtils.formatException(e));
				}
				httpServletResponse.setStatus(500);
				httpServletResponse.setContentType("text/x-json;charset=UTF-8");
				httpServletResponse.getWriter().write(template);
				return;
			}
			log.info("Method doFilter finish");
		}
	}

	/**
	 * @param resource
	 * @param method
	 */
	protected boolean checkPass(HttpServletRequest httpServletRequest) {
		String resource = getResource(httpServletRequest);
		String method = getMethod(httpServletRequest);
		boolean result = false;

		if (isWadl(httpServletRequest)) { // 是否wadl描述
			result = true;
		} else if (!resLib.isEmpty()) {
			for (Iterator iterator = resLib.keySet().iterator(); iterator.hasNext();) {
				String key = (String) iterator.next();
				if (resource.startsWith(key)) {
					if (resLib.get(key) != null && resLib.get(key).indexOf(method) != -1) {
						result = true;
						break;
					}
				}
			}
		} else {
			result = true;
		}
		return result;
	}

	protected boolean isWadl(HttpServletRequest httpServletRequest) {
		boolean result = false;

		String path = httpServletRequest.getQueryString();
		if (path != null && path.toLowerCase().endsWith("_wadl")) {
			result = true;
		}

		return result;
	}

	public void destroy() {
		log.debug("Method destroy()...");
	}

}
